package com.qbb.server.aop;

import java.lang.reflect.Method;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import com.qbb.server.aop.annotation.QbbServer;
import com.qbb.server.aop.bean.MethodConsBean;

public class JavassistUtil {
	private static ClassPool pool = ClassPool.getDefault();

	/**
	 * 根据参数获得方法的定义信息
	 * 
	 * @param clazz
	 * @param methodName
	 * @return
	 */
	public static MethodConsBean getMethodConsBean(Class clazz,
			String methodName) {
		MethodConsBean bean = new MethodConsBean();

		testReflectParamName(bean, clazz, methodName);
		getMethodParamTypes(bean, clazz, methodName);

		return bean;
	}

	/**
	 * 反射获取方法参数名称
	 */
	private static void testReflectParamName(MethodConsBean bean, Class clazz,
			String methodName) {
		try {
			// web javassist.NotFoundException 异常解决办法
			pool.insertClassPath(new ClassClassPath(clazz));
			// declare method
			CtClass cc = pool.get(clazz.getName());
			CtMethod cm = cc.getDeclaredMethod(methodName);

			// 使用javaassist的反射方法获取方法的参数名
			MethodInfo methodInfo = cm.getMethodInfo();
			CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
			LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
					.getAttribute(LocalVariableAttribute.tag);
			if (attr == null) {
				// exception
				return;
			}

			CtClass[] paramTypes = cm.getParameterTypes();
			int paranLen = paramTypes.length;

			String[] paramNames = new String[paranLen];
			int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
			for (int i = 0; i < paranLen; i++) {
				paramNames[i] = attr.variableName(i + pos);
			}
			bean.setInNames(paramNames);
		} catch (NotFoundException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void getMethodParamTypes(MethodConsBean bean, Class clazz,
			String methodName) {
		Method[] methods = clazz.getDeclaredMethods();
		int methodLen = methods.length;

		for (int i = 0; i < methodLen; i++) {
			Method method = methods[i];
			String method_name = method.getName();

			if (!methodName.equals(method_name)) {
				continue;
			}

			Class qbbserverClass = QbbServer.class;

			boolean isAnnFlag = method.isAnnotationPresent(qbbserverClass);
			if (isAnnFlag) {
				// 获取该方法的MyAnnotation注解实例
				QbbServer myAnnotation = (QbbServer) method
						.getAnnotation(qbbserverClass);
				bean.setMyAnnotation(myAnnotation);
			}

			Class returnClas = method.getReturnType();
			String returnTypeStr = returnClas.getSimpleName().toUpperCase();
			if (!returnTypeStr.equals("VOID")) {
				bean.setOutType(returnClas);
			}

			Class[] clas = method.getParameterTypes();
			bean.setInTypes(clas);
			break;
		}
	}
}